
#include "config.hpp"

#include "atr/ext.hpp"

#include "atr/list.hpp"

using namespace atr;
using namespace atr::ext;

#include <list>
#include <map>
#include <vector>

TEST(ExtTest, Initialize_Compile)
{
    std::list<int>  mLInt = initialize<std::list<int>>::with<list< _t(1)
                                                                 , _t(2)>>();
    std::list<char> mLChar = initialize<std::list<char>>::with<list< _t('a')
                                                                   , _t('z')>>();

    UNUSED(mLInt);
    UNUSED(mLChar);
}

TEST(ExtTest, Initialize_Empty)
{
    std::list<int>  mLInt  = initialize<std::list<int>>::with<list<>>();
    std::list<char> mLChar = initialize<std::list<char>>::with<list<>>();

    std::list<int>  eLInt;
    std::list<char> eLChar;

    EXPECT_EQ( eLInt,  mLInt );
    EXPECT_EQ( eLChar, mLChar );
}

TEST(ExtTest, Initialize_Simple)
{
    std::list<int>  mLInt = initialize<std::list<int>>::with<list< _t(1)
                                                                 , _t(2)>>();
    std::list<char> mLChar = initialize<std::list<char>>::with<list< _t('a')
                                                                   , _t('z')>>();

    std::list<int>  eLInt  = {1, 2};
    std::list<char> eLChar = {'a', 'z'};

    EXPECT_EQ( eLInt,  mLInt );
    EXPECT_EQ( eLChar, mLChar );
}

TEST(ExtTest, Initialize_MoreComplex)
{
    std::list<int>  mLInt = initialize<std::list<int>>::with<list< _t(1)
                                                                 , _t('a')
                                                                 , _t(5)
                                                                 , _t(' ')>>();
    std::list<char> mLChar = initialize<std::list<char>>::with<list< _t(1)
                                                                  , _t('a')
                                                                  , _t(5)
                                                                  , _t(' ')>>();

    std::list<int>  eLInt  = {1, 'a', 5, ' '};
    std::list<char> eLChar = {1, 'a', 5, ' '};

    EXPECT_EQ( eLInt,  mLInt );
    EXPECT_EQ( eLChar, mLChar );
}

TEST(ExtTest, Initialize_CrossType)
{
    std::vector<int> mVInt = initialize<std::vector<int>>::with<list< _t(1)
                                                                    , _t(2)
                                                                    , _t('a')
                                                                    , _t(0xff)>>();

    std::vector<int> eVInt = {1, 2, 'a', 0xff};

    EXPECT_EQ( eVInt, mVInt );
}

TEST(ExtTest, Initialize_Combine_Empty)
{
    using mTLInt  = list<>;
    using mTLChar = list<>;

    std::map<int, char> mMap = initialize<std::map<int, char>>::with< mTLInt
                                                                    , mTLChar>();

    std::map<int, char> eMap;

    EXPECT_EQ( eMap, mMap );
}

TEST(ExtTest, Initialize_Combine_Simple)
{
    using mTLInt  = list< _t(1), _t(2), _t(3) >;
    using mTLChar = list< _t('a'), _t('b'), _t('c') >;

    std::map<int, char> mMap = initialize<std::map<int, char>>::with< mTLInt
                                                                    , mTLChar>();

    std::map<int, char> eMap = { {1, 'a'}, {2, 'b'}, {3, 'c'} };

    EXPECT_EQ( eMap, mMap );
}

TEST(ExtTest, Initialize_Combine_MoreComplex)
{
    using mTLInt  = list< _t(1), _t('a'), _t('x') >;
    using mTLChar = list< _t('a'), _t(2), _t(0xff) >;

    std::map<int, char> mMap = initialize<std::map<int, char>>::with< mTLInt
                                                                    , mTLChar>();

    std::map<int, char> eMap = { {1, 'a'}, {'a', 2}, {'x', 0xff} };

    EXPECT_EQ( eMap, mMap );
}

TEST(ExtTest, Initialize_EmptyInput)
{
    std::list<int> list = initialize<std::list<int>>::with<>();

    EXPECT_TRUE( list.empty() );
}

struct CustomStruct
{
    char a;
    int b;
    size_t c;
};

TEST(ExtTest, Initialize_CustomStruct)
{
    using mList = list<_t('d'), _t(5), _t(0xa2)>;

    auto customStruct = initialize<CustomStruct>::with< mList >();

    EXPECT_EQ( 'd', customStruct.a );
    EXPECT_EQ( 5, customStruct.b );
    EXPECT_EQ( 0xa2, customStruct.c );
}